home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / progjrn / pj_7_6.arc / SPLITSCN.ASM < prev    next >
Assembly Source File  |  1989-08-13  |  11KB  |  376 lines

  1. ;
  2. ; *** Listing 1 ***
  3. ;
  4. ; Demonstrates the VGA/EGA split screen in action.
  5. ;
  6. ;*********************************************************************
  7. IS_VGA        equ    1    ;set to 0 to assemble for EGA
  8. ;
  9. VGA_SEGMENT    equ    0a000h
  10. SCREEN_WIDTH    equ    640
  11. SCREEN_HEIGHT    equ    350
  12. CRTC_INDEX    equ    3d4h    ;CRT Controller Index register
  13. OVERFLOW    equ    7    ;index of Overflow reg in CRTC
  14. MAXIMUM_SCAN_LINE equ    9    ;index of Maximum Scan Line register
  15.                 ; in CRTC
  16. START_ADDRESS_HIGH equ    0ch    ;index of Start Address High register
  17.                 ; in CRTC
  18. START_ADDRESS_LOW equ    0dh    ;index of Start Address Low register
  19.                 ; in CRTC
  20. LINE_COMPARE    equ    18h    ;index of Line Compare reg (bits 7-0
  21.                 ; of split screen start scan line)
  22.                 ; in CRTC
  23. INPUT_STATUS_0    equ    3dah    ;Input Status 0 register
  24. WORD_OUTS_OK    equ    1    ;set to 0 to assemble for
  25.                 ; computers that can't handle
  26.                 ; word outs to indexed VGA registers
  27. ;*********************************************************************
  28. ; Macro to output a word value to a port.
  29. ;
  30. OUT_WORD    macro
  31. if WORD_OUTS_OK
  32.     out    dx,ax
  33. else
  34.     out    dx,al
  35.     inc    dx
  36.     xchg    ah,al
  37.     out    dx,al
  38.     dec    dx
  39.     xchg    ah,al
  40. endif
  41.     endm
  42. ;*********************************************************************
  43. MyStack    segment para stack 'STACK'
  44.     db    512 dup (0)
  45. MyStack    ends
  46. ;*********************************************************************
  47. Data    segment
  48. SplitScreenLine    dw    ?    ;line the split screen currently
  49.                 ; starts after
  50. StartAddress    dw    ?    ;display memory offset at which
  51.                 ; scanning for video data starts
  52. ; Message displayed in split screen.
  53. SplitScreenMsg    db    'Split screen text row #'
  54. DigitInsert    dw    ?
  55.         db    '...$'
  56. Data    ends
  57. ;*********************************************************************
  58. Code    segment
  59.     assume    cs:Code, ds:Data
  60. ;*********************************************************************
  61. Start    proc    near
  62.     mov    ax,Data
  63.     mov    ds,ax
  64. ;
  65. ; Select mode 10h, 640x350 16-color graphics mode.
  66. ;
  67.     mov    ax,0010h    ;AH=0 is select mode function
  68.                 ;AL=10h is mode to select,
  69.                 ; 640x350 16-color graphics mode
  70.     int    10h
  71. ;
  72. ; Put text into display memory starting at offset 0, with each row
  73. ; labelled as to number. This is the part of memory that will be
  74. ; displayed in the split screen portion of the display.
  75. ;
  76.     mov    cx,25        ;# of lines of text we'll draw into
  77.                 ; the split screen part of memory
  78. FillSplitScreenLoop:
  79.     mov    ah,2        ;set cursor location function #
  80.     sub    bh,bh        ;set cursor in page 0
  81.     mov    dh,25
  82.     sub    dh,cl        ;calculate row to draw in
  83.     sub    dl,dl        ;start in column 0
  84.     int    10h        ;set the cursor location
  85.     mov    al,25
  86.     sub    al,cl        ;calculate row to draw in again
  87.     sub    ah,ah        ;make the value a word for division
  88.     mov    dh,10
  89.     div    dh        ;split the row # into two digits
  90.     add    ax,'00'        ;convert the digits to ASCII
  91.     mov    [DigitInsert],ax ;put the digits into the text
  92.                 ; to be displayed
  93.     mov    ah,9
  94.     mov    dx,offset SplitScreenMsg
  95.     int    21h        ;print the text
  96.     loop    FillSplitScreenLoop
  97. ;
  98. ; Fill display memory starting at 8000h with a diagonally striped
  99. ; pattern.
  100. ;
  101.     mov    ax,VGA_SEGMENT
  102.     mov    es,ax
  103.     mov    di,8000h
  104.     mov    dx,SCREEN_HEIGHT ;fill all lines
  105.     mov    ax,8888h    ;starting fill pattern
  106.     cld
  107. RowLoop:
  108.     mov    cx,SCREEN_WIDTH/8/2 ;fill 1 scan line a word at a time
  109.     rep    stosw            ;fill the scan line
  110.     ror    ax,1        ;shift pattern word
  111.     dec    dx
  112.     jnz    RowLoop
  113. ;
  114. ; Set the start address to 8000h and display that part of memory.
  115. ;
  116.     mov    [StartAddress],8000h
  117.     call    SetStartAddress
  118. ;
  119. ; Slide the split screen half way up the screen and then back down
  120. ; a quarter of the screen.
  121. ;
  122.     mov    [SplitScreenLine],SCREEN_HEIGHT-1
  123.                     ;set the initial line just off
  124.                     ; the bottom of the screen
  125.     mov    cx,SCREEN_HEIGHT/2
  126.     call    SplitScreenUp
  127.     mov    cx,SCREEN_HEIGHT/4
  128.     call    SplitScreenDown
  129. ;
  130. ; Now move up another half a screen and then back down a quarter.
  131. ;
  132.     mov    cx,SCREEN_HEIGHT/2
  133.     call    SplitScreenUp
  134.     mov    cx,SCREEN_HEIGHT/4
  135.     call    SplitScreenDown
  136. ;
  137. ; Finally move up to the top of the screen.
  138. ;
  139.     mov    cx,SCREEN_HEIGHT/2-2
  140.     call    SplitScreenUp
  141. ;
  142. ; Wait for a key press (don't echo character).
  143. ;
  144.     mov    ah,8    ;DOS console input without echo function
  145.     int    21h
  146. ;
  147. ; Turn the split screen off.
  148. ;
  149.     mov    [SplitScreenLine],0ffffh
  150.     call    SetSplitScreenScanLine
  151. ;
  152. ; Wait for a key press (don't echo character).
  153. ;
  154.     mov    ah,8    ;DOS console input without echo function
  155.     int    21h
  156. ;
  157. ; Display the memory at 0 (the same memory the split screen displays).
  158. ;
  159.     mov    [StartAddress],0
  160.     call    SetStartAddress
  161. ;
  162. ; Flip between the split screen and the normal screen every 10th
  163. ; frame until a key is pressed.
  164. ;
  165. FlipLoop:
  166.     xor    [SplitScreenLine],0ffffh
  167.     call    SetSplitScreenScanLine
  168.     mov    cx,10
  169. CountVerticalSyncsLoop:
  170.     call    WaitForVerticalSyncEnd
  171.     loop    CountVerticalSyncsLoop
  172.     mov    ah,0bh    ;DOS character available status
  173.     int    21h
  174.     and    al,al    ;character available?
  175.     jz    FlipLoop ;no, toggle split screen on/off status
  176.     mov    ah,1
  177.     int    21h    ;clear the character
  178. ;
  179. ; Return to text mode and DOS.
  180. ;
  181.     mov    ax,0003h    ;AH=0 is select mode function
  182.                 ;AL=3 is mode to select, text mode
  183.     int    10h        ;return to text mode
  184.     mov    ah,4ch
  185.     int    21h        ;return to DOS
  186. Start    endp
  187. ;*********************************************************************
  188. ; Waits for the leading edge of the vertical sync pulse.
  189. ;
  190. ; Input: none
  191. ;
  192. ; Output: none
  193. ;
  194. ; Registers altered: AL, DX
  195. ;
  196. WaitForVerticalSyncStart    proc    near
  197.     mov    dx,INPUT_STATUS_0
  198. WaitNotVerticalSync:
  199.     in    al,dx
  200.     test    al,08h
  201.     jnz    WaitNotVerticalSync
  202. WaitVerticalSync:
  203.     in    al,dx
  204.     test    al,08h
  205.     jz    WaitVerticalSync
  206.     ret
  207. WaitForVerticalSyncStart    endp
  208. ;*********************************************************************
  209. ; Waits for the trailing edge of the vertical sync pulse.
  210. ;
  211. ; Input: none
  212. ;
  213. ; Output: none
  214. ;
  215. ; Registers altered: AL, DX
  216. ;
  217. WaitForVerticalSyncEnd    proc    near
  218.     mov    dx,INPUT_STATUS_0
  219. WaitVerticalSync2:
  220.     in    al,dx
  221.     test    al,08h
  222.     jz    WaitVerticalSync2
  223. WaitNotVerticalSync2:
  224.     in    al,dx
  225.     test    al,08h
  226.     jnz    WaitNotVerticalSync2
  227.     ret
  228. WaitForVerticalSyncEnd    endp
  229. ;*********************************************************************
  230. ; Sets the start address to the value specifed by StartAddress.
  231. ; Wait for the trailing edge of vertical sync before setting so that
  232. ; one half of the address isn't loaded before the start of the frame
  233. ; and the other half after, resulting in flicker as one frame is
  234. ; displayed with mismatched halves. The new start address won't be
  235. ; loaded until the start of the next frame; that is, one full frame
  236. ; will be displayed before the new start address takes effect.
  237. ;
  238. ; Input: none
  239. ;
  240. ; Output: none
  241. ;
  242. ; Registers altered: AX, DX
  243. ;
  244. SetStartAddress    proc    near
  245.     call    WaitForVerticalSyncEnd
  246.     mov    dx,CRTC_INDEX
  247.     mov    al,START_ADDRESS_HIGH
  248.     mov    ah,byte ptr [StartAddress+1]
  249.     cli        ;make sure both registers get set at once
  250.     OUT_WORD
  251.     mov    al,START_ADDRESS_LOW
  252.     mov    ah,byte ptr [StartAddress]
  253.     OUT_WORD
  254.     sti
  255.     ret
  256. SetStartAddress    endp
  257. ;*********************************************************************
  258. ; Sets the scan line the split screen starts after to the scan line
  259. ; specified by SplitScreenLine.
  260. ;
  261. ; Input: none
  262. ;
  263. ; Output: none
  264. ;
  265. ; All registers preserved
  266. ;
  267. SetSplitScreenScanLine    proc    near
  268.     push    ax
  269.     push    cx
  270.     push    dx
  271. ;
  272. ; Wait for the leading edge of the vertical sync pulse. This ensures
  273. ; that we don't get mismatched portions of the split screen setting
  274. ; while setting the two or three split screen registers (register 18h
  275. ; set but register 7 not yet set when a match occurs, for example),
  276. ; which could produce brief flickering.
  277. ;
  278.     call    WaitForVerticalSyncStart
  279. ;
  280. ; Set the split screen scan line.
  281. ;
  282.     mov    dx,CRTC_INDEX
  283.     mov    ah,byte ptr [SplitScreenLine]
  284.     mov    al,LINE_COMPARE
  285.     cli        ;make sure all the registers get set at once
  286.     OUT_WORD    ;set bits 7-0 of the split screen scan line
  287.     mov    ah,byte ptr [SplitScreenLine+1]
  288.     and    ah,1
  289.     mov    cl,4
  290.     shl    ah,cl    ;move bit 8 of the split split screen scan
  291.             ; line into position for the Overflow reg
  292.     mov    al,OVERFLOW
  293. if IS_VGA
  294. ;
  295. ; The Split Screen, Overflow, and Line Compare registers all contain
  296. ; part of the split screen start scan line on the VGA. We'll take
  297. ; advantage of the readable registers of the VGA to leave other bits
  298. ; in the registers we access undisturbed.
  299. ;
  300.     out    dx,al    ;set CRTC Index reg to point to Overflow
  301.     inc    dx    ;point to CRTC Data reg
  302.     in    al,dx    ;get the current Overflow reg setting
  303.     and    al,not 10h ;turn off split screen bit 8
  304.     or    al,ah    ;insert the new split screen bit 8
  305.             ; (works in any mode)
  306.     out    dx,al    ;set the new split screen bit 8
  307.     dec    dx    ;point to CRTC Index reg
  308.     mov    ah,byte ptr [SplitScreenLine+1]
  309.     and    ah,2
  310.     mov    cl,3
  311.     ror    ah,cl    ;move bit 9 of the split split screen scan
  312.             ; line into position for the Maximum Scan
  313.             ; Line register
  314.     mov    al,MAXIMUM_SCAN_LINE
  315.     out    dx,al    ;set CRTC Index reg to point to Maximum
  316.             ; Scan Line
  317.     inc    dx    ;point to CRTC Data reg
  318.     in    al,dx    ;get the current Maximum Scan Line setting
  319.     and    al,not 40h ;turn off split screen bit 9
  320.     or    al,ah    ;insert the new split screen bit 9
  321.             ; (works in any mode)
  322.     out    dx,al    ;set the new split screen bit 9
  323. else
  324. ;
  325. ; Only the Split Screen and Overflow registers contain part of the
  326. ; Split Screen start scan line and need to be set on the EGA.
  327. ; EGA registers are not readable, so we have to set the non-split
  328. ; screen bits of the Overflow register to a preset value, in this
  329. ; case the value for 350-scan-line modes.
  330. ;
  331.     or    ah,0fh    ;insert the new split screen bit 8
  332.             ; (only works in 350-scan-line EGA modes)
  333.     OUT_WORD    ;set the new split screen bit 8
  334. endif
  335.     sti
  336.     pop    dx
  337.     pop    cx
  338.     pop    ax
  339.     ret
  340. SetSplitScreenScanLine    endp
  341. ;*********************************************************************
  342. ; Moves the split screen up the specified number of scan lines.
  343. ;
  344. ; Input: CX = # of scan lines to move the split screen up by
  345. ;
  346. ; Output: none
  347. ;
  348. ; Registers altered: CX
  349. ;
  350. SplitScreenUp    proc    near
  351. SplitScreenUpLoop:
  352.     dec    [SplitScreenLine]
  353.     call    SetSplitScreenScanLine
  354.     loop    SplitScreenUpLoop
  355.     ret
  356. SplitScreenUp    endp
  357. ;*********************************************************************
  358. ; Moves the split screen down the specified number of scan lines.
  359. ;
  360. ; Input: CX = # of scan lines to move the split screen down by
  361. ;
  362. ; Output: none
  363. ;
  364. ; Registers altered: CX
  365. ;
  366. SplitScreenDown    proc    near
  367. SplitScreenDownLoop:
  368.     inc    [SplitScreenLine]
  369.     call    SetSplitScreenScanLine
  370.     loop    SplitScreenDownLoop
  371.     ret
  372. SplitScreenDown    endp
  373. ;*********************************************************************
  374. Code    ends
  375.     end    Start
  376.